package com.lx.location.plugin.lx_location_plugin

import android.Manifest
import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry

/** LxLocationPlugin */
class  LxLocationPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.RequestPermissionsResultListener, EventChannel.StreamHandler {

  companion object {
    private const val LOCATION_PERMISSION_REQUEST_CODE = 1001
    private const val TAG = "FlutterLocationTracker"
  }

  private lateinit var channel: MethodChannel

  private lateinit var eventChannel: EventChannel
  private var context: Context? = null
  private var activity: Activity? = null
  private var locationReceiver: BroadcastReceiver? = null
  private var eventSink: EventChannel.EventSink? = null
  private var pendingResult: Result? = null


  override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    context = flutterPluginBinding.applicationContext
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "lx_location_plugin")
    channel.setMethodCallHandler(this)
    eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "lx_location_plugin/location_updates")
    eventChannel.setStreamHandler(this)
  }

  override fun onMethodCall(call: MethodCall, result: Result) {
    if (call.method == "getPlatformVersion") {
      result.success("Android ${android.os.Build.VERSION.RELEASE}")
    } else if (call.method == "startLocationService") {
      Log.d(TAG, "startLocationService called")
      if (hasLocationPermission()) {
        startLocationService()
        result.success("Location service started")
      } else {
        pendingResult = result
        requestLocationPermission()
      }
    } else if (call.method == "stopLocationService") {
      Log.d(TAG, "stopLocationService called")
      stopLocationService()
      result.success("Location service stopped")
    } else {
      result.notImplemented()
    }
  }

  // EventChannel.StreamHandler implementation
  override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
    Log.d(TAG, "EventChannel.onListen called")
    eventSink = events
    locationReceiver = createLocationReceiver(events)

    val intentFilter = IntentFilter(LocationService.LOCATION_UPDATE_ACTION)
    Log.d(TAG, "Registering broadcast receiver for: ${LocationService.LOCATION_UPDATE_ACTION}")

    context?.let { ctx ->
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        ctx.registerReceiver(
          locationReceiver,
          intentFilter,
          Context.RECEIVER_NOT_EXPORTED
        )
      } else {
        ctx.registerReceiver(locationReceiver, intentFilter)
      }
    }
    Log.d(TAG, "Broadcast receiver registered")
  }

  override fun onCancel(arguments: Any?) {
    locationReceiver?.let { receiver ->
      try {
        context?.unregisterReceiver(receiver)
      } catch (e: Exception) {
        Log.e(TAG, "Error unregistering receiver", e)
      }
      locationReceiver = null
    }
    eventSink = null
  }

  private fun hasLocationPermission(): Boolean {
    val context = this.context ?: return false

    val fineLocationGranted = ContextCompat.checkSelfPermission(
      context, Manifest.permission.ACCESS_FINE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED

    val backgroundPermissionGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
      ContextCompat.checkSelfPermission(
        context, Manifest.permission.ACCESS_BACKGROUND_LOCATION
      ) == PackageManager.PERMISSION_GRANTED
    } else {
      true
    }

    return fineLocationGranted && backgroundPermissionGranted
  }

  private fun requestLocationPermission() {
    val activity = this.activity ?: return

    val permissions = mutableListOf<String>()

    if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)
      != PackageManager.PERMISSION_GRANTED
    ) {
      permissions.add(Manifest.permission.ACCESS_FINE_LOCATION)
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
      ContextCompat.checkSelfPermission(
        activity,
        Manifest.permission.ACCESS_BACKGROUND_LOCATION
      )
      != PackageManager.PERMISSION_GRANTED
    ) {
      permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
    }

    if (permissions.isNotEmpty()) {
      ActivityCompat.requestPermissions(
        activity,
        permissions.toTypedArray(),
        LOCATION_PERMISSION_REQUEST_CODE
      )
    } else {
      pendingResult?.success("Location permission already granted")
      pendingResult = null
    }
  }

  private fun startLocationService() {
    val context = this.context ?: return
    Intent(context, LocationService::class.java).also { intent ->
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(intent)
      } else {
        context.startService(intent)
      }
    }
  }

  private fun stopLocationService() {
    val context = this.context ?: return
    Intent(context, LocationService::class.java).also { intent ->
      context.stopService(intent)
    }
  }

  private fun createLocationReceiver(events: EventChannel.EventSink?): BroadcastReceiver {
    return object : BroadcastReceiver() {
      override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "Location broadcast received")

        val latitude = intent.getDoubleExtra(LocationService.EXTRA_LATITUDE, 0.0)
        val longitude = intent.getDoubleExtra(LocationService.EXTRA_LONGITUDE, 0.0)
        val bearing = intent.getFloatExtra(LocationService.EXTRA_BEARING, 0.0f)
        val locTime = intent.getLongExtra(LocationService.EXTRA_LOC_TIME, 0L)
        val altitude = intent.getDoubleExtra(LocationService.EXTRA_ALTITUDE, 0.0)

        Log.d(TAG, "Location data: lat=$latitude, lng=$longitude, bearing=$bearing, time=$locTime, altitude=$altitude")

        val locationData = HashMap<String, Any>()
        locationData["latitude"] = latitude
        locationData["longitude"] = longitude
        locationData["bearing"] = bearing
        locationData["location_time"] = locTime
        locationData["altitude"] = altitude

        try {
          events?.success(locationData)
          Log.d(TAG, "Location data sent to Flutter via EventChannel")
        } catch (e: Exception) {
          Log.e(TAG, "Error sending location data to Flutter", e)
        }
      }
    }
  }

  override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
  ): Boolean {
    if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
      val allGranted = grantResults.isNotEmpty() &&
              grantResults.all { it == PackageManager.PERMISSION_GRANTED }

      if (allGranted) {
        Log.d(TAG, "Location permission granted")
        pendingResult?.success("Location permission granted")
      } else {
        Log.d(TAG, "Location permission denied")
        pendingResult?.success("Location permission denied")
      }
      pendingResult = null
      return true
    }
    return false
  }

  override fun onAttachedToActivity(binding: ActivityPluginBinding) {
    activity = binding.activity
    binding.addRequestPermissionsResultListener(this)
  }

  override fun onDetachedFromActivityForConfigChanges() {
    activity = null
  }

  override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
    activity = binding.activity
    binding.addRequestPermissionsResultListener(this)
  }

  override fun onDetachedFromActivity() {
    activity = null
  }

  override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
    eventChannel.setStreamHandler(null)
    context = null
  }

}

